package com.greenyoung.pwiki.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.greenyoung.pwiki.gateway.utils.EncryptUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 授权过滤器
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    TokenStore tokenStore;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //如果头信息中不含认证信息，直接返回，交由gateway进行路由
        String header = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (header == null || !header.startsWith(OAuth2AccessToken.BEARER_TYPE)) {
            return chain.filter(exchange);
        }

        String token = header.substring((OAuth2AccessToken.BEARER_TYPE + " ").length());
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
        if (oAuth2AccessToken == null) {
            return chain.filter(exchange);
        }
        //如果token过期
        else if (oAuth2AccessToken.isExpired()) {
            return Mono.error(new Exception("Access token expired: " + token));
        }
        OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(oAuth2AccessToken);
        Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
        //取出用户身份信息,里面包含了user对象全部信息的json串
        String principal = userAuthentication.getName();
        //取出用户权限
        List<String> authorities = new ArrayList<>();
        //从userAuthentication取出权限，放在authorities
        userAuthentication.getAuthorities().stream().forEach(c -> authorities.add(((GrantedAuthority) c).getAuthority()));

        OAuth2Request oAuth2Request = oAuth2Authentication.getOAuth2Request();
        Map<String, String> requestParameters = oAuth2Request.getRequestParameters();
        Map<String, Object> jsonToken = new HashMap<>(requestParameters);
        jsonToken.put("principal", principal);
        jsonToken.put("authorities", authorities);

        //把base64编码的token信息写入请求头发送给微服务
        String baseJsonToken = EncryptUtil.encodeUTF8StringBase64(JSON.toJSONString(jsonToken));
        ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeaders -> {
            httpHeaders.add("json-token", baseJsonToken);
        }).build();
        //将现在的request变成change对象
        ServerWebExchange serverWebExchange = exchange.mutate().request(serverHttpRequest).build();

        return chain.filter(serverWebExchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
